﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace System
{
    /// <summary>
    /// 扩展<see cref="Type"/>。
    /// </summary>
    public static partial class Extention
    {
        /// <summary>
        /// 创建<typeparamref name="T"/>类型的实例。
        /// </summary>
        public static T CreateInstance<T>(this Type type, params object[] args)
        {

            return (T)type.CreateInstance(args);
        }

        /// <summary>
        /// 创建<paramref name="type"/>类型的实例。
        /// </summary>
        public static object CreateInstance(this Type type, params object[] args)
        {

            return Activator.CreateInstance(type, args);
        }

        /// <summary>
        /// 是否是具体类型，凡是能直接实例化的类型都是具体类型。
        /// </summary>
        public static bool IsConcreteType(this Type type)
        {

            return
                    !type.IsGenericTypeDefinition
                    &&
                    !type.IsAbstract
                    &&
                    !type.IsInterface;
        }
        /// <summary>
        /// 在<paramref name="type"/>的接口定义中，是否拥有<paramref name="genericInterfaceTypeDefinition"/>指定的泛型接口类型定义 。
        /// </summary>
        public static bool HasGenericInterfaceTypeDefinition(this Type type, Type genericInterfaceTypeDefinition)
        {

            foreach (var item in type.GetInterfaces())
            {
                if (item.IsGenericType
                    &&
                    item.GetGenericTypeDefinition() == genericInterfaceTypeDefinition)
                {
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Determines whether [is base type] [the specified type].
        /// 判断type是否继承baseType
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="baseType">Type of the base.</param>
        /// <returns></returns>
        public static bool IsBaseType(this Type type, Type baseType)
        {
            if (type.BaseType == null || type.BaseType == typeof(System.Object))
                return false;
            if (type.BaseType == baseType)
            {
                if (type.IsAbstract || type.IsInterface)
                    return false;
                return true;
            }
            else
            {
                if (type.BaseType.BaseType != null)
                    return IsBaseType(type.BaseType.BaseType, baseType);
                else
                    return false;
            }
        }
        /// <summary>
        /// 判断指定的类型 <paramref name="type"/> 是否是指定泛型类型的子类型，或实现了指定泛型接口。
        /// </summary>
        /// <param name="type">需要测试的类型。</param>
        /// <param name="generic">泛型接口类型，传入 typeof(IXxx&lt;&gt;)</param>
        /// <returns>如果是泛型接口的子类型，则返回 true，否则返回 false。</returns>
        public static bool IsGeneric(this Type type, Type generic)
        {
            try
            {
                if (type == null || generic == null)
                {
                    return false;
                }
                // 测试接口。
                var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
                if (isTheRawGenericType) return true;

                // 测试类型。
                while (type != null && type != typeof(object))
                {
                    isTheRawGenericType = IsTheRawGenericType(type);
                    if (isTheRawGenericType) return true;
                    type = type.BaseType;
                }

                // 没有找到任何匹配的接口或类型。
                return false;

                // 测试某个类型是否是指定的原始接口。
                bool IsTheRawGenericType(Type test)
                    => generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
            }
            catch (Exception)
            {
                return false;
            }
        }
        /// <summary>
        /// 判断某个类型是否继承自某个父类
        /// </summary>
        /// <param name="type">要判断的类型</param>
        /// <param name="requiredBaseType">基类类型</param>
        public static void AssertTypeInheritance(this Type type, Type requiredBaseType)
        {
            if (!requiredBaseType.IsAssignableFrom(type))
            {
                throw new Exception(string.Format("类型{0}不是一个有效的类型，因为没有继承类型{1}", type.FullName, requiredBaseType.FullName));
            }
        }
        /// <summary>
        ///     判断指定类型是否为数值类型
        /// </summary>
        /// <param name="type">要检查的类型</param>
        /// <returns>是否是数值类型</returns>
        public static bool IsNumeric(this Type type)
        {
            return type == typeof(Byte)
                || type == typeof(Int16)
                || type == typeof(Int32)
                || type == typeof(Int64)
                || type == typeof(SByte)
                || type == typeof(UInt16)
                || type == typeof(UInt32)
                || type == typeof(UInt64)
                || type == typeof(Decimal)
                || type == typeof(Double)
                || type == typeof(Single);
        }

        /// <summary>
        ///  获取成员元数据的Description特性描述信息
        /// </summary>
        /// <param name="member">成员元数据对象</param>
        /// <param name="inherit">是否搜索成员的继承链以查找描述特性</param>
        /// <returns>返回Description特性描述信息，如不存在则返回成员的名称</returns>
        public static string ToDescription(this MemberInfo member, bool inherit = false)
        {
            DescriptionAttribute desc = member.GetAttribute<DescriptionAttribute>(inherit);
            return desc == null ? null : desc.Description;
        }

        /// <summary>
        /// 检查指定指定类型成员中是否存在指定的Attribute特性
        /// </summary>
        /// <typeparam name="T">要检查的Attribute特性类型</typeparam>
        /// <param name="memberInfo">要检查的类型成员</param>
        /// <param name="inherit">是否从继承中查找</param>
        /// <returns>是否存在</returns>
        public static bool AttributeExists<T>(this MemberInfo memberInfo, bool inherit) where T : Attribute
        {
            return memberInfo.GetCustomAttributes(typeof(T), inherit).Any(m => (m as T) != null);
        }

        /// <summary>
        /// 从类型成员获取指定Attribute特性
        /// </summary>
        /// <typeparam name="T">Attribute特性类型</typeparam>
        /// <param name="memberInfo">类型类型成员</param>
        /// <param name="inherit">是否从继承中查找</param>
        /// <returns>存在返回第一个，不存在返回null</returns>
        public static T GetAttribute<T>(this MemberInfo memberInfo, bool inherit) where T : Attribute
        {
            return memberInfo.GetCustomAttributes(typeof(T), inherit).SingleOrDefault() as T;
        }

        /// <summary>
        /// 从类型成员获取指定Attribute特性
        /// </summary>
        /// <typeparam name="T">Attribute特性类型</typeparam>
        /// <param name="memberInfo">类型类型成员</param>
        /// <param name="inherit">是否从继承中查找</param>
        /// <returns>存在返回第一个，不存在返回null</returns>
        public static T[] GetAttributes<T>(this MemberInfo memberInfo, bool inherit) where T : Attribute
        {
            return memberInfo.GetCustomAttributes(typeof(T), inherit).Cast<T>().ToArray();
        }

        public static Assembly GetAssembly(this Type type)
        {
            return type.GetTypeInfo().Assembly;
        }

        public static bool IsNullableType(this Type type)
        {
            return (((type != null) && type.IsGenericType) &&
                (type.GetGenericTypeDefinition() == typeof(Nullable<>)));
        }

        public static Type GetNonNullableType(this Type type)
        {
            if (IsNullableType(type))
            {
                return type.GetGenericArguments()[0];
            }
            return type;
        }

        public static bool IsEnumerableType(this Type enumerableType)
        {
            return (FindGenericType(typeof(IEnumerable<>), enumerableType) != null);
        }

        public static Type GetElementType(this Type enumerableType)
        {
            Type type = FindGenericType(typeof(IEnumerable<>), enumerableType);
            if (type != null)
            {
                return type.GetGenericArguments()[0];
            }
            return enumerableType;
        }

        public static bool IsKindOfGeneric(this Type type, Type definition)
        {
            return (FindGenericType(definition, type) != null);
        }

        public static Type FindGenericType(this Type definition, Type type)
        {
            while ((type != null) && (type != typeof(object)))
            {
                if (type.IsGenericType && (type.GetGenericTypeDefinition() == definition))
                {
                    return type;
                }
                if (definition.IsInterface)
                {
                    foreach (Type type2 in type.GetInterfaces())
                    {
                        Type type3 = FindGenericType(definition, type2);
                        if (type3 != null)
                        {
                            return type3;
                        }
                    }
                }
                type = type.BaseType;
            }
            return null;
        }
        #region 类型扩展
        /// <summary>
        /// 判断属性是否是静态的
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static bool IsStatic(this PropertyInfo property) => (property.GetMethod ?? property.SetMethod).IsStatic;

        /// <summary>
        /// 判断指定类型是否实现于该类型
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="implementType"></param>
        /// <returns></returns>
        public static bool IsImplementType(this Type serviceType, Type implementType)
        {
            //泛型
            if (serviceType.IsGenericType)
            {
                if (serviceType.IsInterface)
                {
                    var interfaces = implementType.GetInterfaces();
                    if (interfaces.Any(m => m.IsGenericType && m.GetGenericTypeDefinition() == serviceType))
                    {
                        return true;
                    }
                }
                else
                {
                    if (implementType.BaseType != null && implementType.BaseType.IsGenericType && implementType.BaseType.GetGenericTypeDefinition() == serviceType)
                    {
                        return true;
                    }
                }
            }
            else
            {
                if (serviceType.IsInterface)
                {
                    var interfaces = implementType.GetInterfaces();
                    if (interfaces.Any(m => m == serviceType))
                        return true;
                }
                else
                {
                    if (implementType.BaseType != null && implementType.BaseType == serviceType)
                        return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 判断是否继承自指定的泛型
        /// </summary>
        /// <param name="type"></param>
        /// <param name="generic"></param>
        /// <returns></returns>
        public static bool IsSubclassOfGeneric(this Type type, Type generic)
        {
            while (type != null && type != typeof(object))
            {
                var cur = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
                if (generic == cur)
                {
                    return true;
                }
                type = type.BaseType;
            }
            return false;
        }

        /// <summary>
        /// 判断是否可空类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsNullable(this Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        }

        /// <summary>
        /// 判断是否是String类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsString(this Type type)
        {
            return type == TypeConst.String;
        }

        /// <summary>
        /// 判断是否是Byte类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsByte(this Type type)
        {
            return type == TypeConst.Byte;
        }

        /// <summary>
        /// 判断是否是Char类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsChar(this Type type)
        {
            return type == TypeConst.Char;
        }

        /// <summary>
        /// 判断是否是Short类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsShort(this Type type)
        {
            return type == TypeConst.Short;
        }

        /// <summary>
        /// 判断是否是Int类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsInt(this Type type)
        {
            return type == TypeConst.Int;
        }

        /// <summary>
        /// 判断是否是Long类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsLong(this Type type)
        {
            return type == TypeConst.Long;
        }

        /// <summary>
        /// 判断是否是Float类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsFloat(this Type type)
        {
            return type == TypeConst.Float;
        }

        /// <summary>
        /// 判断是否是Double类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsDouble(this Type type)
        {
            return type == TypeConst.Double;
        }

        /// <summary>
        /// 判断是否是Decimal类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsDecimal(this Type type)
        {
            return type == TypeConst.Decimal;
        }

        /// <summary>
        /// 判断是否是DateTime类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsDateTime(this Type type)
        {
            return type == TypeConst.DateTime;
        }

        /// <summary>
        /// 判断是否是Guid类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsGuid(this Type type)
        {
            return type == TypeConst.Guid;
        }

        /// <summary>
        /// 判断是否是Bool类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsBool(this Type type)
        {
            return type == TypeConst.Bool;
        }
    }

    /// <summary>
    /// 类型常量
    /// </summary>
    public class TypeConst
    {
        /// <summary>
        /// String
        /// </summary>
        public static readonly Type String = typeof(string);

        /// <summary>
        /// Byte
        /// </summary>
        public static readonly Type Byte = typeof(byte);

        /// <summary>
        /// Char
        /// </summary>
        public static readonly Type Char = typeof(char);

        /// <summary>
        /// Short
        /// </summary>
        public static readonly Type Short = typeof(short);

        /// <summary>
        /// Int
        /// </summary>
        public static readonly Type Int = typeof(int);

        /// <summary>
        /// Long
        /// </summary>
        public static readonly Type Long = typeof(long);

        /// <summary>
        /// Float
        /// </summary>
        public static readonly Type Float = typeof(float);

        /// <summary>
        /// Double
        /// </summary>
        public static readonly Type Double = typeof(double);

        /// <summary>
        /// Decimal
        /// </summary>
        public static readonly Type Decimal = typeof(decimal);

        /// <summary>
        /// DateTime
        /// </summary>
        public static readonly Type DateTime = typeof(DateTime);

        /// <summary>
        /// Guid
        /// </summary>
        public static readonly Type Guid = typeof(Guid);

        /// <summary>
        /// Bool
        /// </summary>
        public static readonly Type Bool = typeof(bool);
        #endregion
    }
}
